1 /* 2 * Collie - An asynchronous event-driven network framework using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: putao's Dlang team 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module collie.bootstrap.client; 12 13 import collie.channel; 14 import collie.net; 15 import collie.utils.memory; 16 17 import collie.bootstrap.exception; 18 import collie.net.client.linklogInfo; 19 public import kiss.net.TcpStream; 20 import kiss.event.task; 21 22 final class ClientBootstrap(PipeLine) : PipelineManager 23 { 24 alias ConnCallBack = void delegate(PipeLine); 25 alias LinklogInfo = TLinklogInfo!ConnCallBack; 26 alias ClientCreatorCallBack = void delegate(TcpStream); 27 28 this(EventLoop loop) 29 { 30 _loop = loop; 31 } 32 33 ~this() 34 { 35 if (_timer) 36 _timer.destroy; 37 if(_logInfo.client) 38 _logInfo.client.destroy; 39 } 40 41 void setClientCreatorCallBack(ClientCreatorCallBack cback) 42 { 43 _oncreator = cback; 44 } 45 46 auto pipelineFactory(shared PipelineFactory!PipeLine pipeFactory) 47 { 48 _pipelineFactory = pipeFactory; 49 return this; 50 } 51 52 /// time is s 53 auto heartbeatTimeOut(uint second) 54 { 55 _timeOut = second * 1000; 56 return this; 57 } 58 59 void connect(Address to, ConnCallBack cback = null) 60 { 61 if (_pipelineFactory is null) 62 throw new NeedPipeFactoryException( 63 "Pipeline must be not null! Please set Pipeline frist!"); 64 if (_logInfo.client) 65 throw new ConnectedException("This Socket is Connected! Please close before connect!"); 66 _logInfo.addr = to; 67 _logInfo.tryCount = 0; 68 _logInfo.cback = cback; 69 _loop.postTask(newTask(&doConnect)); 70 } 71 72 void close() 73 { 74 if (_logInfo.client is null) 75 return; 76 _logInfo.client.close(); 77 } 78 79 @property EventLoop eventLoop() 80 { 81 return _loop; 82 } 83 84 @property auto pipeLine() 85 { 86 if(_logInfo.client is null) 87 return null; 88 return _pipe; 89 } 90 91 @property tryCount(){return _tryCount;} 92 @property tryCount(uint count){_tryCount = count;} 93 94 protected: 95 void doConnect() 96 { 97 _logInfo.client = new TcpStream(_loop,_logInfo.addr.addressFamily); 98 if(_oncreator) 99 _oncreator(_logInfo.client); 100 _logInfo.client.setCloseHandle(&closeCallBack); 101 _logInfo.client.setConnectHandle(&connectCallBack); 102 _logInfo.client.setReadHandle(&readCallBack); 103 _logInfo.client.connect(_logInfo.addr); 104 } 105 106 void closeCallBack() nothrow @trusted 107 { 108 catchAndLogException((){ 109 if (_timer) 110 _timer.stop(); 111 if(_pipe) 112 _pipe.transportInactive(); 113 }()); 114 } 115 116 void connectCallBack(bool isconnect) nothrow @trusted 117 { 118 catchAndLogException((){ 119 if (isconnect) 120 { 121 if (_timeOut > 0) 122 { 123 if (_timer is null) 124 { 125 _timer = new KissTimer(_loop); 126 _timer.setTimerHandle(&onTimeOut); 127 } 128 if(!_timer.watched) { 129 130 bool rv = _timer.start(_timeOut); 131 //logDebug("start timer! : ", rv); 132 } 133 } 134 _logInfo.tryCount = 0; 135 _pipe = _pipelineFactory.newPipeline(_logInfo.client); 136 if(_logInfo.cback) 137 _logInfo.cback(_pipe); 138 _pipe.finalize(); 139 _pipe.pipelineManager(this); 140 _pipe.transportActive(); 141 }else if(_logInfo.tryCount < _tryCount){ 142 _logInfo.client = null; 143 _logInfo.tryCount ++; 144 doConnect(); 145 } else { 146 if(_logInfo.cback) 147 _logInfo.cback(null); 148 _logInfo.client = null; 149 _logInfo.cback = null; 150 _logInfo.addr = null; 151 _pipe = null; 152 } 153 }()); 154 } 155 156 void readCallBack(in ubyte[] buffer) nothrow @trusted 157 { 158 catchAndLogException(_pipe.read(cast(ubyte[])buffer)); 159 } 160 /// Client Time out is not refresh! 161 void onTimeOut() nothrow @trusted 162 { 163 catchAndLogException((){ 164 if(_pipe) 165 _pipe.timeOut(); 166 }()); 167 } 168 169 override void deletePipeline(PipelineBase pipeline) 170 { 171 if (_timer) 172 _timer.stop(); 173 gcFree(_logInfo.client); 174 _logInfo.client = null; 175 pipeline.pipelineManager(null); 176 _pipe = null; 177 } 178 179 override void refreshTimeout() 180 { 181 } 182 183 private: 184 EventLoop _loop; 185 PipeLine _pipe; 186 shared PipelineFactory!PipeLine _pipelineFactory; 187 KissTimer _timer = null; 188 uint _timeOut = 0; 189 uint _tryCount; 190 191 LinklogInfo _logInfo; 192 ClientCreatorCallBack _oncreator; 193 }